Here's another fun and confusing crash:
[adiumx.git] / Frameworks / Adium Framework / NDComponentInstance.m
blobf0f6dfe917f399458ae7d38431fcee3c689aa92f
1 /*
2  *  NDComponentInstance.m
3  *  NDAppleScriptObjectProject
4  *
5  *  Created by Nathan Day on Tue May 20 2003.
6  *  Copyright (c) 2002 Nathan Day. All rights reserved.
7  */
9 #import "NDComponentInstance.h"
10 #import "NSAppleEventDescriptor+NDAppleScriptObject.h"
11 #include "NDProgrammerUtilities.h"
13 const OSType            kFinderCreatorCode = 'MACS';
15 const NSString          * NDAppleScriptOffendingObject = @"Error Offending Object",
16                                                 * NDAppleScriptPartialResult = @"Error Partial Result";
19  * function AppleScriptActiveProc
20  */
21 static OSErr AppleScriptActiveProc( long aRefCon )
23         NDComponentInstance     * self = (id)aRefCon;
24         id                                                      theActiveTarget = [self activeTarget];
25         OSErr                                           theError = errOSASystemError;
27         NSCParameterAssert( self != nil );
28         
29         if( theActiveTarget != nil )
30                 theError = [theActiveTarget appleScriptActive] ? noErr : errOSASystemError;
31         else
32                 theError = (self->defaultActiveProcPtr)( self->defaultActiveProcRefCon );
34         return theError;
37 static OSErr AppleEventResumeHandler(const AppleEvent * anAppleEvent, AppleEvent * aReply, long aRefCon )
39         NDComponentInstance                                                     * self = (id)aRefCon;
40         OSErr                                                                           theError = errAEEventNotHandled;
41         id <NDScriptDataAppleEventResumeHandler>        theResumeHandler = [self appleEventResumeHandler];
42         NSAppleEventDescriptor                                          * theResult = nil;
44         NSCParameterAssert( self != nil );
46         if( theResumeHandler == nil )
47                 theResumeHandler = self;
49         theResult = [theResumeHandler handleResumeAppleEvent:[NSAppleEventDescriptor descriptorWithAEDesc:anAppleEvent]];
50         
51         if( theResult )
52         {
53                 NSCParameterAssert( [theResult getAEDesc:aReply] );
54                 theError = noErr;
55         }
56         else
57                 theError = errOSASystemError;
58         
59         return theError;
63  * category interface NDComponentInstance (Private)
64  */
65 @interface NDComponentInstance (Private)
66 - (ComponentInstance)instanceRecord;
67 @end
70  * class implementation NDComponentInstance
71  */
72 @implementation NDComponentInstance
74 static NDComponentInstance              * sharedComponentInstance = nil;
77  * +sharedComponentInstance
78  */
79 + (id)sharedComponentInstance
81         if( sharedComponentInstance == nil )
82                 sharedComponentInstance = [[self alloc] init];
83         NSAssert( sharedComponentInstance != nil, @"Could not create shared Component Instance" );
84         return sharedComponentInstance;
88  * +closeSharedComponentInstance
89  */
90 + (void)closeSharedComponentInstance
92         [sharedComponentInstance release];
93         sharedComponentInstance = nil;
97  * findNextComponent
98  */
99 + (Component)findNextComponent
101         ComponentDescription            theReturnCompDesc;
102         static Component                        theLastComponent = NULL;
103         ComponentDescription            theComponentDesc;
105         theComponentDesc.componentType = kOSAComponentType;
106         theComponentDesc.componentSubType = kOSAGenericScriptingComponentSubtype;
107         theComponentDesc.componentManufacturer = 0;
108         theComponentDesc.componentFlags =  kOSASupportsCompiling | kOSASupportsGetSource | kOSASupportsAECoercion | kOSASupportsAESending | kOSASupportsConvenience | kOSASupportsDialects | kOSASupportsEventHandling;
110         theComponentDesc.componentFlagsMask = theComponentDesc.componentFlags;
112         do
113         {
114                 theLastComponent = FindNextComponent( theLastComponent, &theComponentDesc );
115         }
116         while( GetComponentInfo( theLastComponent, &theReturnCompDesc, NULL, NULL, NULL ) == noErr && theComponentDesc.componentSubType == kOSAGenericScriptingComponentSubtype );
118         return theLastComponent;
122  * + componentInstance
123  */
124 + (id)componentInstance
126         return [[[self alloc] init] autorelease];
130  * +componentInstanceWithComponent:
131  */
132 + (id)componentInstanceWithComponent:(Component)aComponent
134         return [[[self alloc] initWithComponent:aComponent] autorelease];
138  * -init
139  */
140 - (id)init
142         return [self initWithComponent:NULL];
146  * -initWithComponent:
147  */
148 - (id)initWithComponent:(Component)aComponent
150         if( (self = [super init]) != nil )
151         {
152                 if( aComponent == NULL )
153                 {
154                         // crashes here
155                         if( (instanceRecord = OpenDefaultComponent( kOSAComponentType, kAppleScriptSubtype )) == NULL )
156                         {
157                                 [self release];
158                                 self = nil;
159                                 NSLog(@"Could not open connection with default AppleScript component");
160                         }
161                 }
162                 else if( (instanceRecord = OpenComponent( aComponent )) == NULL )
163                 {
164                         [self release];
165                         self = nil;
166                         NSLog(@"Could not open connection with component");
167                 }
168         }
169         return self;
173  * - dealloc
174  */
175 -(void)dealloc
177         [self setAppleEventSendTarget:nil];
178         [self setActiveTarget:nil];
179 //      [self setAppleEventSpecialHandler:nil];
180         [self setAppleEventResumeHandler:nil];
181                 
182         if( instanceRecord != NULL )
183         {
184                 CloseComponent( instanceRecord );
185         }
186         [super dealloc];
190  * - setDefaultTarget:
191  */
192 - (void)setDefaultTarget:(NSAppleEventDescriptor *)aDefaultTarget
194         if( OSASetDefaultTarget( [self instanceRecord], [aDefaultTarget aeDesc] ) != noErr )
195                 NSLog( @"Could not set default target" );
199  * - setDefaultTargetAsCreator:
200  */
201 - (void)setDefaultTargetAsCreator:(OSType)aCreator
203         NSAppleEventDescriptor  * theAppleEventDescriptor;
205         theAppleEventDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplSignature data:[NSData dataWithBytes:&aCreator length:sizeof(aCreator)]];
206         [self setDefaultTarget:theAppleEventDescriptor];
210  * - setFinderAsDefaultTarget
211  */
212 - (void)setFinderAsDefaultTarget
214         [self setDefaultTargetAsCreator:kFinderCreatorCode];
217 - (void)setAppleEventSendTarget:(id<NDScriptDataSendEvent>)aTarget
219         [self setAppleEventSendTarget:aTarget currentProcessOnly:NO];
223  * setAppleEventSendTarget:
224  */
225 - (void)setAppleEventSendTarget:(id<NDScriptDataSendEvent>)aTarget currentProcessOnly:(BOOL)aFlag;
227         sendAppleEvent.currentProcessOnly = aFlag;
228         if( aTarget != sendAppleEvent.target )
229         {
230                 OSErr           AppleEventSendProc( const AppleEvent *theAppleEvent, AppleEvent *reply, AESendMode sendMode, AESendPriority sendPriority, long timeOutInTicks, AEIdleUPP idleProc, AEFilterUPP filterProc, long refCon );
232                 NSParameterAssert( sizeof(long) == sizeof(id) );
233                 
234                 /*      need to save the default send proceedure as we will call it in our send proceedure      */
235                 if( aTarget != nil )
236                 {
237                         if( defaultSendProcPtr == NULL )                // need to save this so we can restor it
238                         {
239                                 OSASendUPP                                              theDefaultSendProcPtr;
240                                 long int                                                        theDefaultSendProcRefCon;
241                                 ComponentInstance               theComponent = [self instanceRecord];
243                                 NSAssert( OSAGetSendProc( theComponent, &theDefaultSendProcPtr, &theDefaultSendProcRefCon) == noErr, @"Could not get default AppleScript send procedure");
244                                 
245                                 /*
246                                  * make sure we haven't already set the send procedure for this component instance.
247                                  */
248                                 if( theDefaultSendProcPtr != AppleEventSendProc )
249                                 {
250                                         defaultSendProcPtr = theDefaultSendProcPtr;
251                                         defaultSendProcRefCon = theDefaultSendProcRefCon;
252                                 }
253                                 else    // get the original component instance
254                                 {
255                                         NSLog( @"The send procedure for this component instance is already set." );
256                                         defaultSendProcPtr = ((NDComponentInstance*)theDefaultSendProcRefCon)->defaultSendProcPtr;
257                                         defaultSendProcRefCon = ((NDComponentInstance*)theDefaultSendProcRefCon)->defaultSendProcRefCon;
258                                 }
259                                 NSAssert( OSASetSendProc( theComponent, AppleEventSendProc, (long)self ) == noErr, @"Could not set send procedure" );
260                         }
262                         [sendAppleEvent.target release];
263                         sendAppleEvent.target = [aTarget retain];
264                 }
265                 else
266                 {
267                         [sendAppleEvent.target release];
268                         sendAppleEvent.target = nil;
270                         NSAssert( OSASetSendProc( [self instanceRecord], defaultSendProcPtr, defaultSendProcRefCon ) == noErr, @"Could not restore default send procedure");
272                         defaultSendProcPtr = NULL;
273                         defaultSendProcRefCon = 0;
274                 }
275         }
279  * appleEventSendTarget
280  */
281 - (id<NDScriptDataSendEvent>)appleEventSendTarget
283         return sendAppleEvent.target;
286 - (BOOL)appleEventSendCurrentProcessOnly
288         return sendAppleEvent.currentProcessOnly;
292  * setActiveTarget:
293  */
294 - (void)setActiveTarget:(id<NDScriptDataActive>)aTarget
296         if( aTarget != activeTarget )
297         {
298                 NSParameterAssert( sizeof(long) == sizeof(id) );
300                 if( aTarget != nil )
301                 {
302                         /*      need to save the default active proceedure as we will call it in our active proceedure  */
303                         if( defaultActiveProcPtr == NULL )
304                         {
305                                 ComponentInstance               theComponent = [self instanceRecord];
307                                 NSAssert( OSAGetActiveProc(theComponent, &defaultActiveProcPtr, &defaultActiveProcRefCon ) == noErr, @"Could not get default AppleScript active procedure");
308                                 NSAssert( OSASetActiveProc( theComponent, AppleScriptActiveProc , (long)self ) == noErr, @"Could not set AppleScript active procedure.");
309                         }
311                         [activeTarget release];
312                         activeTarget = [aTarget retain];
313                 }
314                 else if( defaultActiveProcPtr == NULL )
315                 {
316                         [activeTarget release];
317                         activeTarget = nil;
318                         NSAssert( OSASetActiveProc( [self instanceRecord], defaultActiveProcPtr, defaultActiveProcRefCon ) == noErr, @"Could not set default active procedure.");
319                         defaultActiveProcPtr = NULL;
320                         defaultActiveProcRefCon = 0;
321                 }
322         }
326  * -activeTarget
327  */
328 - (id<NDScriptDataActive>)activeTarget
330         return activeTarget;
333 #if 0
335  * -setAppleEventSpecialHandler:
336  */
337 - (void)setAppleEventSpecialHandler:(id<NDScriptDataAppleEventSpecialHandler>)aHandler
339         if( aHandler != appleEventSpecialHandler )
340         {
341                 [appleEventSpecialHandler release];
342                 appleEventSpecialHandler = [aHandler retain];
343         }
347  * -appleEventSpecialHandler
348  */
349 - (id<NDScriptDataAppleEventSpecialHandler>)appleEventSpecialHandler
351         return appleEventSpecialHandler;
353 #endif
356  * -setAppleEventResumeHandler:
357  */
358 - (void)setAppleEventResumeHandler:(id<NDScriptDataAppleEventResumeHandler>)aHandler
360         if( aHandler != appleEventResumeHandler )
361         {
362                 if( defaultResumeProcPtr == NULL )
363                         NDLogOSStatus( OSAGetResumeDispatchProc ( [self instanceRecord], &defaultResumeProcPtr, &defaultResumeProcRefCon ) );
365                 NDLogOSStatus( OSASetResumeDispatchProc( [self instanceRecord], AppleEventResumeHandler, (long int)self ) );
366                 [(NSObject *)appleEventResumeHandler release];
367                 appleEventResumeHandler = [(NSObject *)aHandler retain];
368         }
372  * -appleEventResumeHandler
373  */
374 - (id<NDScriptDataAppleEventResumeHandler>)appleEventResumeHandler
376         return appleEventResumeHandler;
380  * -sendAppleEvent:sendMode:sendPriority:timeOutInTicks:idleProc:filterProc:
381  */
382 - (NSAppleEventDescriptor *)sendAppleEvent:(NSAppleEventDescriptor *)anAppleEventDescriptor sendMode:(AESendMode)aSendMode sendPriority:(AESendPriority)aSendPriority timeOutInTicks:(long)aTimeOutInTicks idleProc:(AEIdleUPP)anIdleProc filterProc:(AEFilterUPP)aFilterProc
384         NSAppleEventDescriptor          * theReplyAppleEventDescriptor = nil;
385         AEDesc                                                  theReplyDesc = { typeNull, NULL };
387         NSParameterAssert( defaultSendProcPtr != NULL );
388         
389 //      if( NDLogOSStatus( defaultSendProcPtr( [anAppleEventDescriptor aeDesc], &theReplyDesc, aSendMode, aSendPriority, aTimeOutInTicks, anIdleProc, aFilterProc, defaultSendProcRefCon ) ) )
390         NDLogOSStatus( defaultSendProcPtr( [anAppleEventDescriptor aeDesc], &theReplyDesc, aSendMode, aSendPriority, aTimeOutInTicks, anIdleProc, aFilterProc, defaultSendProcRefCon ) );
391         {
392                 theReplyAppleEventDescriptor = [NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theReplyDesc];
393         }
394         
395         return theReplyAppleEventDescriptor;
399  * appleScriptActive
400  */
401 - (BOOL)appleScriptActive
403         NSParameterAssert( defaultActiveProcPtr != NULL );
404         return defaultActiveProcPtr( defaultActiveProcRefCon ) == noErr;
408  * -handleResumeAppleEvent:
409  */
410 - (NSAppleEventDescriptor *)handleResumeAppleEvent:(NSAppleEventDescriptor *)aDescriptor
412         AEDesc          theReplyDesc = { typeNull, NULL };
413         return defaultResumeProcPtr([aDescriptor aeDesc], &theReplyDesc, defaultResumeProcRefCon ) == noErr ? [NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theReplyDesc] : nil;
418  * -error
419  */
420 - (NSDictionary *)error
422         AEDesc                                  theDescriptor = { typeNull, NULL };
423         unsigned int                    theIndex;
424         NSMutableDictionary     * theDictionary = [NSMutableDictionary dictionaryWithCapacity:7];
426         struct { const NSString * key; const DescType desiredType; const OSType selector; }
427                         theResults[] = {
428                         { NSAppleScriptErrorMessage, typeText, kOSAErrorMessage },
429                         { NSAppleScriptErrorNumber, typeShortInteger, kOSAErrorNumber },
430                         { NSAppleScriptErrorAppName, typeText, kOSAErrorApp },
431                         { NSAppleScriptErrorBriefMessage, typeText, kOSAErrorBriefMessage },
432                         { NSAppleScriptErrorRange, typeOSAErrorRange, kOSAErrorRange },
433                         { NDAppleScriptOffendingObject, typeObjectSpecifier, kOSAErrorOffendingObject, },
434                         { NDAppleScriptPartialResult, typeBest, kOSAErrorPartialResult },
435                         { nil, 0, 0 }
436                         };
437         for( theIndex = 0; theResults[theIndex].key != nil; theIndex++ )
438         {
439                 if( OSAScriptError([self instanceRecord], theResults[theIndex].selector, theResults[theIndex].desiredType, &theDescriptor ) == noErr )
440                 {
441                         [theDictionary setObject:(id)[[NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theDescriptor] objectValue] forKey:(id)theResults[theIndex].key];
442                 }
443         }
445         return theDictionary;
449  * -name
450  */
451 - (NSString *)name
453         AEDesc          theDesc = { typeNull, NULL };
454         NSString                * theName = nil;
455         if ( OSAScriptingComponentName( [self instanceRecord], &theDesc) == noErr )
456                 theName = [[NSAppleEventDescriptor descriptorWithAEDescNoCopy:&theDesc] stringValue];
458         return theName;
462  * description
463  */
464 - (NSString *)description
466         NSString                * theName = [self name];
467         return theName == nil
468                 ? [@"NDComponentInstance name:" stringByAppendingString:theName]
469                 : @"NDComponentInstance name: not available";
473  * -isEqualToComponentInstance:
474  */
475 - (BOOL)isEqualToComponentInstance:(NDComponentInstance *)aComponentInstance
477         return aComponentInstance == self || [aComponentInstance instanceRecord] == [self instanceRecord];
481  * -isEqualTo:
482  */
483 - (BOOL)isEqualTo:(id)anObject
485         return anObject == self || ([anObject isKindOfClass:[self class]] && [self isEqualToComponentInstance:anObject]);
489  * -copyWithZone:
490  */
491 - (id)copyWithZone:(NSZone *)aZone
493         return [self retain];
497  * -hash
498  */
499 - (unsigned int)hash
501         return (unsigned int)instanceRecord;
505  * function AppleEventSendProc
506  */
507 OSErr AppleEventSendProc( const AppleEvent *anAppleEvent, AppleEvent *aReply, AESendMode aSendMode, AESendPriority aSendPriority, long aTimeOutInTicks, AEIdleUPP anIdleProc, AEFilterUPP aFilterProc, long aRefCon )
509         NDComponentInstance                     * self = (id)aRefCon;
510         OSErr                                                           theError = errOSASystemError;
511         id                                                                      theSendTarget = [self appleEventSendTarget];
512         BOOL                                                            theCurrentProcessOnly = [self appleEventSendCurrentProcessOnly];
513         NSAppleEventDescriptor          * theAppleEventDescReply,
514                                                                                 * theAppleEventDescriptor = [[NSAppleEventDescriptor alloc] initWithAEDesc:anAppleEvent];
516         NSCParameterAssert( self != nil );
518         /*      if we have an instance, it has a target and we can create a NSAppleEventDescriptor      */
519         if( theSendTarget != nil && theAppleEventDescriptor != nil && (theCurrentProcessOnly == NO || [theAppleEventDescriptor isTargetCurrentProcess]) )
520         {       
521                 theAppleEventDescReply = [theSendTarget sendAppleEvent:theAppleEventDescriptor sendMode:aSendMode sendPriority:aSendPriority timeOutInTicks:aTimeOutInTicks idleProc:anIdleProc filterProc:aFilterProc];
523                 if( [theAppleEventDescReply getAEDesc:(AEDesc*)aReply] )
524                 {
525                         theError = noErr;                       // NO ERROR
526                 }
527         }
528         else if( self->defaultSendProcPtr != NULL )
529         {
530                 NDLogOSStatus(theError = (self->defaultSendProcPtr)( anAppleEvent, aReply, aSendMode, aSendPriority, aTimeOutInTicks, anIdleProc, aFilterProc, self->defaultSendProcRefCon ));
531         }
532         else
533                 NSLog( @"Failed to send" );
534         
535         [theAppleEventDescriptor release];
537         return theError;
540 #if 0
541 static OSErr AppleEventSpecialHandler(const AppleEvent * anAppleEvent, AppleEvent * aReply, long aRefCon )
543         NDComponentInstance                     * self = (id)aRefCon;
544         OSErr                                                           theError = errAEEventNotHandled;
545         id                                                                      theSpecialHandler = [self appleEventSpecialHandler];
546         NSAppleEventDescriptor          * theResult = nil;
547         
548         NSCParameterAssert( self != nil );
550         if( theSpecialHandler == nil )
551                 theSpecialHandler = self;
552         
553         theResult = [theSpecialHandler handleSpecialAppleEvent:[NSAppleEventDescriptor descriptorWithAEDesc:anAppleEvent]];
554         if( theResult )
555         {
556                 NSCParameterAssert( [theResult getAEDesc:aReply] );
557                 theError = noErr;
558         }
559         else
560                 theError = errOSASystemError;
561         
562         return theError;
564 #endif
566 @end
569  * category implementation NDComponentInstance (Private)
570  */
571 @implementation NDComponentInstance (Private)
574  * -instanceRecord
575  */
576 - (ComponentInstance)instanceRecord
578         return instanceRecord;
581 @end